//
//  Common.swift
//  iOSDemo
//
//  Created by FH on 2020/9/2.
//  Copyright © 2020 Fuhan. All rights reserved.
//

import Foundation

public typealias Action = () -> ()
public typealias Action1<T> = (T) -> ()
public typealias Action2<T1, T2> = (T1, T2) -> ()
public typealias Action3<T1, T2, T3> = (T1, T2, T3) -> ()
public typealias Action4<T1, T2, T3, T4> = (T1, T2, T3, T4) -> ()
public typealias Function<U> = () -> U
public typealias Function1<T, U> = (T) -> U
public typealias Function2<T1, T2, U> = (T1, T2) -> U
public typealias Function3<T1, T2, T3, U> = (T1, T2, T3) -> U
public typealias Function4<T1, T2, T3, T4, U> = (T1, T2, T3, T4) -> U

func call<Input, Output>(_ function: (Input) -> Output, with input: Input) -> Output {
    return function(input)
}
func call<Input>(_ function: (Input) -> Void, with input: Input?) {
    if let input = input {
        call(function, with: input)
    }
}

public enum Union2<T1, T2> {
    case Value1(T1)
    case Value2(T2)
}
public enum Union3<T1, T2, T3> {
    case Value1(T1)
    case Value2(T2)
    case Value3(T3)
}
public enum Union4<T1, T2, T3, T4> {
    case Value1(T1)
    case Value2(T2)
    case Value3(T3)
    case Value4(T4)
}

//////////////////////////////////////

let MainSpecificKey = DispatchSpecificKey<String>()
let MainSpecificValue = "__MainSpecificValue__"

func isRunInMainQueue() -> Bool {
    if let specificValue = DispatchQueue.getSpecific(key: MainSpecificKey),
        specificValue == MainSpecificValue {
        return true
    }
    return false
}

var Debug_Is_Locked = false
public struct Mutex {
    private let semaphore = DispatchSemaphore(value: 1)
    public init() { }
    
    public func lock() {
        if Debug_Is_Locked {
            print(">>> find dead lock ...")
        }
        semaphore.wait()
        Debug_Is_Locked = true
    }
    
    public func unlock() {
        Debug_Is_Locked = false
        semaphore.signal()
    }
    
    public func tryLock() -> Bool {
        return semaphore.wait(timeout: (DispatchTime.now() + 0.001)) == .success
    }
}

//////////////////////////////////////

protocol Copyable {
    init(instance: Self)
}

extension Copyable {
    func copy() -> Self {
        return Self.init(instance: self)
    }
}

public protocol StatesStoreable {
    func setState(_ state: Any, byKey: String, sectionName: String)
}

protocol Serializable {
    func encodeJson() -> String?
    func decodeJson(_ json: String) -> Any?
}

protocol RawEnumConvertible {
    var anyRawValue: Any { get }
    
    static func createInstance(by anyValue: Any) -> Self?
}

extension RawEnumConvertible where Self: RawRepresentable {
    var anyRawValue: Any {
        return self.rawValue
    }
    
    static func createInstance(by anyValue: Any) -> Self? {
        if let castValue = anyValue as? Self.RawValue {
            return Self.init(rawValue: castValue)
        } else if let convertable = Self.RawValue.self as? TypeConvertible.Type,
                  let realTypeValue = convertable.tryConvert(value: anyValue),
                  let castValue = realTypeValue as? Self.RawValue {
            return Self.init(rawValue: castValue)
        } else if let caseValue = anyValue as? Self {
            return caseValue
        }
        return nil
    }
}

protocol TypeConvertible {
    static func convert(value: Any?) -> Self
    static func tryConvert(value: Any?) -> Self?
}

extension Int : TypeConvertible {
    static func convert(value: Any?) -> Int {
        if let strValue = value as? String {
            return Int(strValue)!
        }
        return value as! Self
    }
    
    static func tryConvert(value: Any?) -> Int? {
        if let strValue = value as? String {
            return Int(strValue)
        }
        return value as? Self
    }
}


extension UInt : TypeConvertible {
    static func convert(value: Any?) -> UInt {
        if let strValue = value as? String {
            return UInt(strValue)!
        } else if let intValue = value as? Int {
            return UInt(intValue)
        }
        return value as! Self
    }
    
    static func tryConvert(value: Any?) -> UInt? {
        if let strValue = value as? String {
            return UInt(strValue)
        } else if let intValue = value as? Int {
            return UInt(intValue)
        }
        return value as? Self
    }
}

extension Float : TypeConvertible {
    static func convert(value: Any?) -> Float {
        if let strValue = value as? String {
            return Float(strValue)!
        } else if let doubleValue = value as? Double {
            return Float(doubleValue)
        }
        return value as! Self
    }
    
    static func tryConvert(value: Any?) -> Float? {
        if let strValue = value as? String {
            return Float(strValue)
        } else if let doubleValue = value as? Double {
            return Float(doubleValue)
        }
        return value as? Self
    }
}

protocol TypeComparerible {
    func greater(rhs: TypeComparerible) -> Bool
    func greaterAndEquals(rhs: TypeComparerible) -> Bool
    func less(rhs: TypeComparerible) -> Bool
    func lessAndEquals(rhs: TypeComparerible) -> Bool
}

extension Int : TypeComparerible {
    func greater(rhs: TypeComparerible) -> Bool {
        if let rhsValue = rhs as? Int {
            return self > rhsValue
        }
        return false
    }
    
    func greaterAndEquals(rhs: TypeComparerible) -> Bool {
        if let rhsValue = rhs as? Int {
            return self >= rhsValue
        }
        return false
    }
    
    func less(rhs: TypeComparerible) -> Bool {
        if let rhsValue = rhs as? Int {
            return self < rhsValue
        }
        return false
    }
    
    func lessAndEquals(rhs: TypeComparerible) -> Bool {
        if let rhsValue = rhs as? Int {
            return self <= rhsValue
        }
        return false
    }
}

extension UInt : TypeComparerible {
    func greater(rhs: TypeComparerible) -> Bool {
        if let rhsValue = rhs as? UInt {
            return self > rhsValue
        }
        return false
    }
    
    func greaterAndEquals(rhs: TypeComparerible) -> Bool {
        if let rhsValue = rhs as? UInt {
            return self >= rhsValue
        }
        return false
    }
    
    func less(rhs: TypeComparerible) -> Bool {
        if let rhsValue = rhs as? UInt {
            return self < rhsValue
        }
        return false
    }
    
    func lessAndEquals(rhs: TypeComparerible) -> Bool {
        if let rhsValue = rhs as? UInt {
            return self <= rhsValue
        }
        return false
    }
}

extension Float : TypeComparerible {
    func greater(rhs: TypeComparerible) -> Bool {
        if let rhsValue = rhs as? Float {
            return self > rhsValue
        }
        return false
    }
    
    func greaterAndEquals(rhs: TypeComparerible) -> Bool {
        if let rhsValue = rhs as? Float {
            return self >= rhsValue
        }
        return false
    }
    
    func less(rhs: TypeComparerible) -> Bool {
        if let rhsValue = rhs as? Float {
            return self < rhsValue
        }
        return false
    }
    
    func lessAndEquals(rhs: TypeComparerible) -> Bool {
        if let rhsValue = rhs as? Float {
            return self <= rhsValue
        }
        return false
    }
}

extension Double : TypeComparerible {
    func greater(rhs: TypeComparerible) -> Bool {
        if let rhsValue = rhs as? Double {
            return self > rhsValue
        }
        return false
    }
    
    func greaterAndEquals(rhs: TypeComparerible) -> Bool {
        if let rhsValue = rhs as? Double {
            return self >= rhsValue
        }
        return false
    }
    
    func less(rhs: TypeComparerible) -> Bool {
        if let rhsValue = rhs as? Double {
            return self < rhsValue
        }
        return false
    }
    
    func lessAndEquals(rhs: TypeComparerible) -> Bool {
        if let rhsValue = rhs as? Double {
            return self <= rhsValue
        }
        return false
    }
}

extension String : TypeComparerible {
    func greater(rhs: TypeComparerible) -> Bool {
        if let rhsValue = rhs as? String {
            return self > rhsValue
        }
        return false
    }
    
    func greaterAndEquals(rhs: TypeComparerible) -> Bool {
        if let rhsValue = rhs as? String {
            return self >= rhsValue
        }
        return false
    }
    
    func less(rhs: TypeComparerible) -> Bool {
        if let rhsValue = rhs as? String {
            return self < rhsValue
        }
        return false
    }
    
    func lessAndEquals(rhs: TypeComparerible) -> Bool {
        if let rhsValue = rhs as? String {
            return self <= rhsValue
        }
        return false
    }
}

public class Stack<Element> {
    private(set) var storage: [Element] = []
    
    var count: Int {
        return storage.count
    }
    
    var isEmpty: Bool {
        return storage.count == 0
    }
    
    func top() -> Element? {
        return storage.last
    }
    
    func peek(num: UInt) -> Element? {
        for _ in 0..<num {
            self.pop()
        }
        return self.top()
    }
    
    func push(item: Element) {
        storage.append(item)
    }
    
    @discardableResult
    func pop() -> Element? {
        return storage.popLast()
    }
    
    func enqueue(item: Element) {
        storage.insert(item, at: 0)
    }
    
    func dequeue() -> Element? {
        if storage.count > 0 {
            return storage.removeFirst()
        } else {
            return nil
        }
    }
}

extension Stack : CustomDebugStringConvertible {
    public var debugDescription: String {
        return "stack's count is \(storage.count)"
    }
}

protocol Sectionable {
    associatedtype SectionType
    associatedtype ItemType
    
    var items: [ItemType] { get set }
}

class SectionModel<SectionType, ItemType> : Sectionable {
    var title: String?
    var section: SectionType?
    var items: [ItemType]
    
    init(_ items: [ItemType], _ title: String?=nil, _ section: SectionType?=nil) {
        self.items = items
        self.title = title
        self.section = section
    }
}

extension SectionModel : CustomDebugStringConvertible {
    var debugDescription: String {
        if let title = self.title {
            return "\(title), items(\(items.count))"
        } else {
            return "items(\(items.count))"
        }
    }
}

extension Array where Element: Sectionable {
    func flatten() -> [Element.ItemType] {
        var allItems = [Element.ItemType]()
        for section in self {
            allItems.append(contentsOf: section.items)
        }
        return allItems
    }
}

func buildSection<ItemType>(_ items: [ItemType], title: String?=nil) -> SectionModel<Void, ItemType> {
    return SectionModel(items, title)
}

func buildSection<SectionType, ItemType>(_ items: [ItemType], title: String?=nil, section: SectionType?=nil)
    -> SectionModel<SectionType, ItemType> {
    return SectionModel(items, title, section)
}

struct AnyEncodable: Encodable {
    let value: Encodable
    
    init(_ value: Encodable) {
        self.value = value
    }

    func encode(to encoder: Encoder) throws {
        try value.encode(to: encoder)
    }
}

struct AnyEncodeObject: Encodable {
    let items: [String: AnyEncodable]
    
    func encode(to encoder: Encoder) throws {
        try items.encode(to: encoder)
    }
}

struct AnyEncodeList: Encodable {
    let items: [AnyEncodable]
    
    func encode(to encoder: Encoder) throws {
        try items.encode(to: encoder)
    }
}

enum SimpleError : Error, CustomStringConvertible {
    case stringException(String)
    
    var description: String {
        if case let .stringException(desc) = self {
            return desc
        }
        return ""
    }
}

//////////////////////////////////////

class Score {
    var score: Int = Int.min
    var reason: String = ""
    var matchs: [Score] = []
    
    var isEmpty: Bool {
        return score == Int.min && reason.count == 0
    }
    
    func add(_ score: Int, reason: String) {
        self.score = score
        self.reason = reason
    }
    
    func add(_ score: Score) {
        self.matchs.append(score)
    }
}

extension Score : Comparable {
    static func < (lhs: Score, rhs: Score) -> Bool {
        return lhs.score < rhs.score
    }
    
    static func == (lhs: Score, rhs: Score) -> Bool {
        return lhs.score == rhs.score
    }
}

extension Optional where Wrapped == String {
    var isEmpty: Bool {
        return self == nil || self!.isEmpty
    }
}

extension Int {
    func isPrime() -> Bool {
        let n = self
        guard n > 2     else { return false }
        guard n != 2     else { return true  }
        guard n % 2 != 0 else { return false }
        return !stride(from: 3, through: Int(sqrt(Double(n))), by: 2).contains { n % $0 == 0 }
    }
}

extension String {
    func getSubstring(from: Int, to: Int) -> String {
        let start = index(startIndex, offsetBy: from)
        let end = index(start, offsetBy: to - from + 1)
        return String(self[start ..< end])
    }
    
    func getSubstring(to: Int) -> String {
        return self.getSubstring(from: 0, to: to)
    }
    
    func getSubstring(from: Int) -> String {
        return self.getSubstring(from: from, to: self.count - 1)
    }
    
    // for button after call NSAlert
    func switchButtonTitle() -> String {
        if let lastChar = self.last, lastChar == " " {
            return self.trimWhiteSpaces()
        } else {
            return "\(self) "
        }
    }
    
    func trim(_ chars: String...) -> String {
        var charset = CharacterSet()
        for item in chars {
            charset.insert(item.unicodeScalars.first!)
        }
        return self.trimmingCharacters(in: charset)
    }
    
    func trimWhiteSpaces() -> String {
        return self.trimmingCharacters(in: .whitespacesAndNewlines)
    }
    
    func trimString() -> String {
        return self.trim("\"", "\'")
    }
    
    func indent() -> Int {
        var count = 0
        for char in self {
            if char == " " {
                count += 1
            } else {
                break
            }
        }
        return count
    }
    
    func isBoolean() -> Bool {
        return Bool(self) != nil
    }
    
    func isNumber() -> Bool {
        return Int(self) != nil || UInt(self) != nil || Float(self) != nil || Double(self) != nil
    }
    
    func isInputString() -> Bool {
        return (self.starts(with: "\"") && self.hasSuffix("\""))
                || (self.starts(with: "\'") && self.hasSuffix("\'"))
    }
    
    func checkBoolean() -> Any? {
        let val: Any? = Bool(self)
        return val
    }
    
    func checkNumber() -> Any? {
        var val: Any? = nil
        if let result = Int(self) {
            val = result
        } else if let result = UInt(self) {
            val = result
        } else if let result = Float(self) {
            val = result
        } else if let result = Double(self) {
            val = result
        }
        return val
    }
    
    func checkInputString() -> Any? {
        if self.isInputString() {
            return self.trimString()
        } else {
            return nil
        }
    }
    
    func toNotificationName() -> Notification.Name {
        return Notification.Name(self)
    }
    
    func toJSONObject() -> [String : Any]? {
        return self.toJSON() as? [String : Any]
    }
    
    func toJSONList() -> [Any]? {
        return self.toJSON() as? [Any]
    }
    
    private func toJSON() -> Any? {
        if let data = self.data(using: .utf8), let json = try? JSONSerialization.jsonObject(with: data, options: .allowFragments) {
            // format `"\"{\\\"scenarioSetting\\\":` to `"{\"scenarioSetting\":`
            if let formatString = json as? String {
                return formatString.toJSON()
            } else if (json is NSDictionary) || (json is NSArray) {
                return json
            }
        }
        return nil
    }
    
    // TODO: 可以简单的先支持gap = ". - _"，或者说认为这三个分隔符的造成的score惩罚最小
    func fuzzyMatch(_ needle: String) -> Bool {
        if needle.isEmpty { return false }
        let remainder = needle[...]
        var pos = 0
        for char in self {
            let index =  remainder.index(remainder.startIndex, offsetBy: pos)
            let testChar = remainder[index]
            if char == testChar || char.lowercased() == testChar.lowercased() {
                pos += 1
                if pos == needle.count {
                    return true
                }
            } else if pos > 0 {
                pos = 0
            }
        }
        return false
    }
    
    func fuzzyMatch2(_ needle: Substring, gap: Int?) -> Score? {
        guard !needle.isEmpty else {
            return Score()
        }
        guard !self.isEmpty else { return nil }

        let skipScore = { String(self.dropFirst()).fuzzyMatch2(needle, gap: gap.map { $0 + 1 }) }
        if self.first == needle.first {
            guard let s = String(self.dropFirst()).fuzzyMatch2(needle.dropFirst(), gap: 0)
                else { return nil }
            let acceptScore = Score()
            if let g = gap, g > 0 {
                acceptScore.add(-g, reason: "Gap \(g)")
            }
            acceptScore.add(1, reason: "Match \(first!)")
            acceptScore.add(s)
            
            guard let skip = skipScore() else { return acceptScore }
            return Swift.max(skip, acceptScore)
        } else {
            return skipScore()
        }
    }
    
    func fuzzMatch3(_ needle: String) -> FuzzyScore? {
        var scores = [FuzzyScore]()
        for c in self {
            if c == needle.first {
                let score = FuzzyScore(needle)
                scores.append(score)
            }
            for score in scores {
                score.match(c)
                if score.isPerfectMatched {
                    return score
                }
            }
        }
        if scores.count == 0 {
            return nil
        } else {
            return scores.sorted { (lhs, rhs) in return lhs.score > rhs.score }.first!
        }
    }
}

// TODO: remove
class FuzzyScore {
    private let needle: String
    private let maxScore: Int
    private var matchScores = [Int]()
    private var pos = 0
    private var hGap = 0
    private var vGap = 0
    private (set) var score = Int.min
    
    var isMatched: Bool {
        return self.score != Int.min
    }
    
    var isPerfectMatched: Bool {
        return self.score == self.maxScore
    }
    
    init(_ needle: String) {
        self.needle = needle
        self.maxScore = ((1 + needle.count) * needle.count) * 1000 / 2
    }
    
    fileprivate func match(_ c: Character) {
        
    }
}

extension Notification.Name : ExpressibleByStringLiteral {
    public init(stringLiteral value: StringLiteralType) {
        self = Notification.Name(value)
    }
}

extension Dictionary {
    var allKeys: [Key] {
        return Array(self.keys)
    }
    
    var allValues: [Value] {
        return Array(self.values)
    }
    
    func filterByKeys <C: Collection> (keys: C) -> [Key:Value] where C.Iterator.Element == Key {
        var result = [Key : Value](minimumCapacity: keys.count)
        for key in keys { result[key] = self[key] }
        return result
    }
    
    func mergeValues(by dict: [Key : Value]) -> [Key : Value] {
        var result = self
        for (key, value) in dict {
            result[key] = value
        }
        return result
    }
}

extension Dictionary where Key == String, Value == Any {
    func toQueryString() -> String {
        var urlVars = [String]()
        for (key, value) in self {
            var valueStr: String!
            if let str = value as? String {
                valueStr = str
            } else {
                valueStr = String(reflecting: value)
            }
            
            if let encodedValue = valueStr.addingPercentEncoding(withAllowedCharacters: NSCharacterSet.urlQueryAllowed) {
                urlVars.append(key + "=" + encodedValue)
            }
        }
        return urlVars.isEmpty ? "" : "?" + urlVars.joined(separator: "&")
    }
    
    func formatJSONString() -> String? {
        if let data = try? JSONSerialization.data(withJSONObject: self, options: []),
           let jsonStr = String(data: data, encoding: .utf8) {
            return jsonStr
        }
        return nil
    }
}

extension Dictionary where Key == String, Value == String {
    func formatJSONString() -> String? {
        let dict = self as [String : Any]
        return dict.formatJSONString()
    }
    
    func equals(rhs: [String : String]) -> Bool {
        if self.count == rhs.count {
            for (key, value) in self {
                if let rhsValue = rhs[key], value == rhsValue {
                    continue
                } else {
                    return false
                }
            }
            return true
        }
        return false
    }
}

protocol IntRange {
    var type: String { get }
    var lowerValue: Int? { get }
    var upperValue: Int? { get }
    
    func contains(element: Int) -> Bool
    func decode() -> String
}

func encodeIntRange(with data: String) -> IntRange? {
    let split = data.components(separatedBy: "@")
    if split.count == 2 {
        let type = split[0]
        let valueSplit = split[1].components(separatedBy: ",")
        if valueSplit.count == 2 {
            let lower = valueSplit[0]
            let upper = valueSplit[1]
            if type == "Range", let lowerValue = Int(lower), let upperValue = Int(upper) {
                return lowerValue..<upperValue
            } else if type == "ClosedRange", let lowerValue = Int(lower), let upperValue = Int(upper) {
                return lowerValue...upperValue
            } else if type == "PartialRangeFrom", let lowerValue = Int(lower) {
                return lowerValue...
            } else if type == "PartialRangeThrough", let upperValue = Int(upper) {
                return ...upperValue
            } else if type == "PartialRangeUpTo", let upperValue = Int(upper) {
                return ..<upperValue
            }
        }
    }
    return nil
}

// TODO: IntRange -> AnyRange
extension IntRange {
    func decode() -> String {
        let lower = self.lowerValue == nil ? "?" : "\(self.lowerValue!)"
        let upper = self.upperValue == nil ? "?" : "\(self.upperValue!)"
        return "\(self.type)@\(lower),\(upper)"
    }
    
    func equals(rhs: IntRange) -> Bool {
        return self.type == rhs.type && self.lowerValue == rhs.lowerValue && self.upperValue == rhs.upperValue
    }
}

extension Range: IntRange where Bound == Int {
    var type: String { return "Range" }
    var lowerValue: Int? { return self.lowerBound }
    var upperValue: Int? { return self.upperBound }
    
    func contains(element: Int) -> Bool {
        return self.contains(element)
    }
}

extension ClosedRange: IntRange where Bound == Int {
    var type: String { return "ClosedRange" }
    var lowerValue: Int? { return self.lowerBound }
    var upperValue: Int? { return self.upperBound }
    
    func contains(element: Int) -> Bool {
        return self.contains(element)
    }
}

extension PartialRangeFrom : IntRange where Bound == Int {
    var type: String { return "PartialRangeFrom" }
    var lowerValue: Int? { return self.lowerBound }
    var upperValue: Int? { return nil }
    
    func contains(element: Int) -> Bool {
        return self.contains(element)
    }
}

extension PartialRangeThrough : IntRange where Bound == Int {
    var type: String { return "PartialRangeThrough" }
    var lowerValue: Int? { return nil }
    var upperValue: Int? { return self.upperBound }
    
    func contains(element: Int) -> Bool {
        return self.contains(element)
    }
}

extension PartialRangeUpTo : IntRange where Bound == Int {
    var type: String { return "PartialRangeUpTo" }
    var lowerValue: Int? { return nil }
    var upperValue: Int? { return self.upperBound }
    
    func contains(element: Int) -> Bool {
        return self.contains(element)
    }
}

//////////////////////////////////////

func requestGet(from urlString: String,
                parameters: [String : Any]) -> IOMonad<(Data, URLResponse)> {
    return IOMonad { thunker in
        var request = URLRequest(url: URL(string: urlString + parameters.toQueryString())!)
        request.httpMethod = "GET"
        let session = URLSession.shared.dataTask(with: request) {data, response, err in
            if let error = err {
                thunker.sendError(error)
            } else if let data = data, let response = response {
                thunker.sendNext((data, response))
                thunker.sendComplete()
            }
        }
        session.resume()
        return {
            session.cancel()
        }
    }
}

//////////////////////////////////////

let Tuple2Regex = try! Regex(pattern: #"\((.+?),\s*(.+?)\)"#, groupNames: "item1", "item2")
let Tuple3Regex = try! Regex(pattern: #"\((.+?),\s*(.+?),\s*(.+?)\)"#, groupNames: "item1", "item2", "item3")
let Tuple4Regex = try! Regex(pattern: #"\((.+?),\s*(.+?),\s*(.+?),\s*(.+?)\)"#, groupNames: "item1", "item2", "item3", "item4")

// REMARK: MacOS-Only

#if os(OSX)

struct KeyboardCode {
    // Layout-independent Keys
    // eg.These key codes are always the same key on all layouts.
    static let returnKey                 : UInt16 = 0x24
    static let enter                     : UInt16 = 0x4C
    static let tab                       : UInt16 = 0x30
    static let space                     : UInt16 = 0x31
    static let delete                    : UInt16 = 0x33
    static let escape                    : UInt16 = 0x35
    static let command                   : UInt16 = 0x37
    static let shift                     : UInt16 = 0x38
    static let capsLock                  : UInt16 = 0x39
    static let option                    : UInt16 = 0x3A
    static let control                   : UInt16 = 0x3B
    static let rightShift                : UInt16 = 0x3C
    static let rightOption               : UInt16 = 0x3D
    static let rightControl              : UInt16 = 0x3E
    static let leftArrow                 : UInt16 = 0x7B
    static let rightArrow                : UInt16 = 0x7C
    static let downArrow                 : UInt16 = 0x7D
    static let upArrow                   : UInt16 = 0x7E
    static let volumeUp                  : UInt16 = 0x48
    static let volumeDown                : UInt16 = 0x49
    static let mute                      : UInt16 = 0x4A
    static let help                      : UInt16 = 0x72
    static let home                      : UInt16 = 0x73
    static let pageUp                    : UInt16 = 0x74
    static let forwardDelete             : UInt16 = 0x75
    static let end                       : UInt16 = 0x77
    static let pageDown                  : UInt16 = 0x79
    static let function                  : UInt16 = 0x3F
    static let f1                        : UInt16 = 0x7A
    static let f2                        : UInt16 = 0x78
    static let f4                        : UInt16 = 0x76
    static let f5                        : UInt16 = 0x60
    static let f6                        : UInt16 = 0x61
    static let f7                        : UInt16 = 0x62
    static let f3                        : UInt16 = 0x63
    static let f8                        : UInt16 = 0x64
    static let f9                        : UInt16 = 0x65
    static let f10                       : UInt16 = 0x6D
    static let f11                       : UInt16 = 0x67
    static let f12                       : UInt16 = 0x6F
    static let f13                       : UInt16 = 0x69
    static let f14                       : UInt16 = 0x6B
    static let f15                       : UInt16 = 0x71
    static let f16                       : UInt16 = 0x6A
    static let f17                       : UInt16 = 0x40
    static let f18                       : UInt16 = 0x4F
    static let f19                       : UInt16 = 0x50
    static let f20                       : UInt16 = 0x5A
    
    // US-ANSI Keyboard Positions
    // eg. These key codes are for the physical key (in any keyboard layout)
    // at the location of the named key in the US-ANSI layout.
    static let a                         : UInt16 = 0x00
    static let b                         : UInt16 = 0x0B
    static let c                         : UInt16 = 0x08
    static let d                         : UInt16 = 0x02
    static let e                         : UInt16 = 0x0E
    static let f                         : UInt16 = 0x03
    static let g                         : UInt16 = 0x05
    static let h                         : UInt16 = 0x04
    static let i                         : UInt16 = 0x22
    static let j                         : UInt16 = 0x26
    static let k                         : UInt16 = 0x28
    static let l                         : UInt16 = 0x25
    static let m                         : UInt16 = 0x2E
    static let n                         : UInt16 = 0x2D
    static let o                         : UInt16 = 0x1F
    static let p                         : UInt16 = 0x23
    static let q                         : UInt16 = 0x0C
    static let r                         : UInt16 = 0x0F
    static let s                         : UInt16 = 0x01
    static let t                         : UInt16 = 0x11
    static let u                         : UInt16 = 0x20
    static let v                         : UInt16 = 0x09
    static let w                         : UInt16 = 0x0D
    static let x                         : UInt16 = 0x07
    static let y                         : UInt16 = 0x10
    static let z                         : UInt16 = 0x06

    static let zero                      : UInt16 = 0x1D
    static let one                       : UInt16 = 0x12
    static let two                       : UInt16 = 0x13
    static let three                     : UInt16 = 0x14
    static let four                      : UInt16 = 0x15
    static let five                      : UInt16 = 0x17
    static let six                       : UInt16 = 0x16
    static let seven                     : UInt16 = 0x1A
    static let eight                     : UInt16 = 0x1C
    static let nine                      : UInt16 = 0x19
    
    static let equals                    : UInt16 = 0x18
    static let minus                     : UInt16 = 0x1B
    static let semicolon                 : UInt16 = 0x29
    static let apostrophe                : UInt16 = 0x27
    static let comma                     : UInt16 = 0x2B
    static let period                    : UInt16 = 0x2F
    static let forwardSlash              : UInt16 = 0x2C
    static let backslash                 : UInt16 = 0x2A
    static let grave                     : UInt16 = 0x32
    static let leftBracket               : UInt16 = 0x21
    static let rightBracket              : UInt16 = 0x1E
    
    static let keypadDecimal             : UInt16 = 0x41
    static let keypadMultiply            : UInt16 = 0x43
    static let keypadPlus                : UInt16 = 0x45
    static let keypadClear               : UInt16 = 0x47
    static let keypadDivide              : UInt16 = 0x4B
    static let keypadEnter               : UInt16 = 0x4C
    static let keypadMinus               : UInt16 = 0x4E
    static let keypadEquals              : UInt16 = 0x51
    static let keypad0                   : UInt16 = 0x52
    static let keypad1                   : UInt16 = 0x53
    static let keypad2                   : UInt16 = 0x54
    static let keypad3                   : UInt16 = 0x55
    static let keypad4                   : UInt16 = 0x56
    static let keypad5                   : UInt16 = 0x57
    static let keypad6                   : UInt16 = 0x58
    static let keypad7                   : UInt16 = 0x59
    static let keypad8                   : UInt16 = 0x5B
    static let keypad9                   : UInt16 = 0x5C
}

#endif
